#include <sstream>
#include "BTreeNode.h"

using namespace std;

// Read the content of the node from the page pid in the PageFile pf.
RC BTLeafNode::read(PageId pid, const PageFile& pf) {
	RC ret = pf.read(pid, buffer); // read from pagefile
	stringstream bufStream(buffer);
	int i = 0;
	RecordId buf_rid;
	PageId buf_pid;
	int buf_sid;
	int buf_key = 1;
	while (buf_key > 0) {
		bufStream >> buf_pid;
		bufStream >> buf_sid;
		bufStream >> buf_key;
		buf_rid.pid = buf_pid;
		buf_rid.sid = buf_sid;
		if (buf_key > 0) {
			rid_array[i] = buf_rid;
			key_array[i] = buf_key;
		}
		i++;
	}
	bufStream >> buf_pid;
	nnpt = buf_pid;
	return ret; // Return 0 if successful; error code if error
}
    
// Write the content of the node to the page pid in the PageFile pf.
RC BTLeafNode::write(PageId pid, PageFile& pf) {
	strcpy(buffer, "");
	int i = 0;
	stringstream outStream(buffer);
	while (key_array[i] > 0) {
		outStream << rid_array[i].pid;
		outStream << " ";
		outStream << rid_array[i].sid;
		outStream << " ";
		outStream << key_array[i];
		outStream << "\n";
		i++;
	}
	outStream << nnpt;
	RC ret = pf.write(pid, buffer); // write from buffer
	return ret; // Return 0 if successful; error code if error
}

// Return the number of keys stored in the node.
int BTLeafNode::getKeyCount() {
	int i = 0;
	while (key_array[i] > 0) {
		i++;
	}
	return i;
}

// Insert a (key, rid) pair to the node.
RC BTLeafNode::insert(int key, const RecordId& rid) {
	int num = getKeyCount();
	int i = 0;
	while (key > key_array[i]) {
		i++;
	}
	RecordId temp_rid, temp_rid2;
	int temp_key, temp_key2;
	temp_rid = rid_array[i];
	temp_key = key_array[i];
	rid_array[i] = rid;
	key_array[i] = key;
	int last = i;
	while (i < num) {
		temp_rid2 = rid_array[i];
		temp_key2 = key_array[i];
		rid_array[i] = temp_rid;
		key_array[i] = temp_key;
		temp_rid = temp_rid2;
		temp_key = temp_key2;
		i++;
	}
	if (i > last) {
		rid_array[i] = temp_rid;
		key_array[i] = temp_key;
	}
	return 0;
}

// Insert the (key, rid) pair to the node
// and split the node half and half with sibling.
// The first key of the sibling node is returned in siblingKey.
RC BTLeafNode::insertAndSplit(int key, const RecordId& rid, BTLeafNode& sibling, int& siblingKey) {
	insert(key, rid);
	int num = getKeyCount();
	int k = num / 2;
	int j = num - k;
	int i = 0;
	siblingKey = key_array[j];
	while (j < num) {
		sibling.rid_array[i] = rid_array[j];
		sibling.key_array[i] = key_array[j];
		key_array[j] = 0;
		j++;
		i++;
	}
	return 0;
}

// Find the entry whose key value is larger than or equal to searchKey
// and output the eid (entry number) whose key value >= searchKey.
RC BTLeafNode::locate(int searchKey, int& eid) {
	int i = 0;
	while (key_array[i] > 0) {
		if (key_array[i] >= searchKey)
			return i;
		i++;
	}
	return -1;
}

// Read the (key, rid) pair from the eid entry.
RC BTLeafNode::readEntry(int eid, int& key, RecordId& rid) {
	if (key_array[eid] > 0) {
		key = key_array[eid];
		rid = rid_array[eid];
		return 0;
	}
	return -1;
}

// Return the pid of the next sibling node.
PageId BTLeafNode::getNextNodePtr() {
	return nnpt;
}

// Set the pid of the next sibling node.
RC BTLeafNode::setNextNodePtr(PageId pid) {
	nnpt = pid;
	return 0;
}



// Read the content of the node from the page pid in the PageFile pf.
RC BTNonLeafNode::read(PageId pid, const PageFile& pf) {
	RC ret = pf.read(pid, buffer); // read from pagefile
	stringstream bufStream(buffer);
	int i = 0;
	PageId buf_pid;
	int buf_key = 1;
	while (buf_key > 0) {
		bufStream >> buf_pid;
		bufStream >> buf_key;
		if (buf_key > 0) {
			pid_array[i] = buf_pid;
			key_array[i] = buf_key;
		}
		i++;
	}
	bufStream >> buf_pid;
	pid_array[i] = buf_pid;
	return ret; // Return 0 if successful; error code if error
}
    
// Write the content of the node to the page pid in the PageFile pf.
RC BTNonLeafNode::write(PageId pid, PageFile& pf) {
	strcpy(buffer, "");
	int i = 0;
	stringstream outStream(buffer);
	while (key_array[i] > 0) {
		outStream << pid_array[i];
		outStream << " ";
		outStream << key_array[i];
		outStream << "\n";
		i++;
	}
	outStream << pid_array[i];
	RC ret = pf.write(pid, buffer); // write from buffer
	return ret; // Return 0 if successful; error code if error
}

// Return the number of keys stored in the node.
int BTNonLeafNode::getKeyCount() {
	int i = 0;
	while (key_array[i] > 0) {
		i++;
	}
	return i;
}

// Insert a (key, pid) pair to the node.
RC BTNonLeafNode::insert(int key, PageId pid) {
	int num = getKeyCount();
	int i = 0;
	while (key > key_array[i]) {
		i++;
	}
	PageId temp_pid, temp_pid2;
	int temp_key, temp_key2;
	temp_pid = pid_array[i+1];
	temp_key = key_array[i];
	pid_array[i+1] = pid;
	key_array[i] = key;
	int last = i;
	while (i < num) {
		temp_pid2 = pid_array[i+1];
		temp_key2 = key_array[i];
		pid_array[i+1] = temp_pid;
		key_array[i] = temp_key;
		temp_pid = temp_pid2;
		temp_key = temp_key2;
		i++;
	}
	if (i > last) {
		pid_array[i+1] = temp_pid;
		key_array[i] = temp_key;
	}
	return 0;
}

// Insert the (key, pid) pair to the node
// and split the node half and half with sibling.
// The middle key after the split is returned in midKey.
RC BTNonLeafNode::insertAndSplit(int key, PageId pid, BTNonLeafNode& sibling, int& midKey) {
	insert(key, pid);
	int num = getKeyCount();
	int j = num / 2;
	int i = 0;
	midKey = key_array[j];
	key_array[j] = 0;
	j++;
	while (j < num) {
		sibling.pid_array[i] = pid_array[j];
		sibling.key_array[i] = key_array[j];
		key_array[j] = 0;
		j++;
		i++;
	}
	sibling.pid_array[i] = pid_array[j];
	return 0;
}

// Given the searchKey, find the child-node pointer to follow and
// output it in pid.
RC BTNonLeafNode::locateChildPtr(int searchKey, PageId& pid) {
	int i = 0;
	while (key_array[i] > 0) {
		if (key_array[i] > searchKey) {
			pid = pid_array[i];
			return 0;
		}
		i++;
	}
	pid = pid_array[i];
	return 0;
}

// Initialize the root node with (pid1, key, pid2).
RC BTNonLeafNode::initializeRoot(PageId pid1, int key, PageId pid2) {
	pid_array[0] = pid1;
	key_array[0] = key;
	pid_array[1] = pid2;
	return 0;
}
